package cn.szsys.integration.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author Ryan
 */
public class RSAUtil {


    // 将公钥转换为字符串
    public static String getPublicKeyString(PublicKey publicKey) {
        JSONObject jsonObject = JSON.parseObject("");
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }

    // 将私钥转换为字符串
    public static String getPrivateKeyString(PrivateKey privateKey) {
        return Base64.getEncoder().encodeToString(privateKey.getEncoded());
    }

    // 从字符串恢复公钥
    public static PublicKey getPublicKeyFromString(String publicKeyStr) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    // 从字符串恢复私钥
    public static PrivateKey getPrivateKeyFromString(String privateKeyStr) throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }

    // 使用私钥进行解密
    public static String decrypt(String encryptedText, PrivateKey privateKey) throws Exception {
        Cipher decryptCipher = Cipher.getInstance("RSA");
        decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
        int decryptMaxBlockSize = (2048 / 8);
        byte[] decryptedBytes = new byte[0];
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
        for (int i = 0; i < encryptedBytes.length; i += decryptMaxBlockSize) {
            int length = Math.min(decryptMaxBlockSize, encryptedBytes.length - i);
            byte[] block = new byte[length];
            System.arraycopy(encryptedBytes, i, block, 0, length);
            byte[] decryptedBlock = decryptCipher.doFinal(block);
            byte[] temp = new byte[decryptedBytes.length + decryptedBlock.length];
            System.arraycopy(decryptedBytes, 0, temp, 0, decryptedBytes.length);
            System.arraycopy(decryptedBlock, 0, temp, decryptedBytes.length, decryptedBlock.length);
            decryptedBytes = temp;
        }
        return new String(decryptedBytes);
    }

    public static String decrypt(String encryptedText, String privateKey) throws Exception {
        return decrypt(encryptedText, getPrivateKeyFromString(privateKey));
    }

    // 使用私钥进行校验签名
    public static boolean verifySignature(String data, String signature, PublicKey publicKey) throws Exception {
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(publicKey);
        sig.update(data.getBytes());
        byte[] signatureBytes = Base64.getDecoder().decode(signature);
        return sig.verify(signatureBytes);
    }

    public static boolean verifySignature(String data, String signature, String publicKey) throws Exception {
        return verifySignature(data,signature,getPublicKeyFromString(publicKey));
    }

    // 使用公钥进行加密
    public static String encrypt(String plainText, PublicKey publicKey) throws Exception {
        byte[] plainTextBytes = plainText.getBytes(StandardCharsets.UTF_8);

        // 创建 Cipher 对象并初始化为加密模式
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        // 计算每次加密的最大块大小
        int maxBlockSize = (2048 / 8) - 11; // RSA 2048 密钥，减去填充字节
        byte[] encryptedBytes = new byte[0];

        // 分段加密
        for (int i = 0; i < plainTextBytes.length; i += maxBlockSize) {
            int length = Math.min(maxBlockSize, plainTextBytes.length - i);
            byte[] block = new byte[length];
            System.arraycopy(plainTextBytes, i, block, 0, length);
            byte[] encryptedBlock = cipher.doFinal(block);
            byte[] temp = new byte[encryptedBytes.length + encryptedBlock.length];
            System.arraycopy(encryptedBytes, 0, temp, 0, encryptedBytes.length);
            System.arraycopy(encryptedBlock, 0, temp, encryptedBytes.length, encryptedBlock.length);
            encryptedBytes = temp;
        }
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public static String encrypt(String plainText, String publicKey) throws Exception {
        return encrypt(plainText, getPublicKeyFromString(publicKey));
    }

    // 使用私钥生成签名
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        byte[] signedBytes = signature.sign();
        return Base64.getEncoder().encodeToString(signedBytes);
    }

    public static String sign(String data, String privateKey) throws Exception {
        return sign(data,getPrivateKeyFromString(privateKey));
    }


//    public static String privateKeyStrtest = "";
//    public static String publicKeyStrtest = "";

//    public static void main(String[] args) {
//        try {
//
//            PublicKey publicKey = getPublicKeyFromString(publicKeyStrtest);
//            PrivateKey privateKey = getPrivateKeyFromString(privateKeyStrtest);
//            // 3. 准备要处理的数据
//            String originalData = "123";
//
//            // 4. 使用公钥加密数据
//            String encryptedData = encrypt(originalData, publicKey);
//            System.out.println("加密后的数据: " + encryptedData);
//
//            // 5. 使用私钥对原始数据进行签名
//            String signature = sign(originalData, privateKey);
//            System.out.println("生成的签名: " + signature);
//
//            // 6. 使用公钥校验签名
//            boolean signatureVerified = verifySignature(originalData, signature, publicKey);
//            System.out.println("签名校验结果: " + signatureVerified);
//
//            // 7. 使用私钥解密数据
//            String decryptedData = decrypt(encryptedData, privateKey);
//            System.out.println("解密后的数据: " + decryptedData);
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
}
